// 安装依赖 pnpm add -D @babel/core @types/babel-types @types/babel__core @types/babel__traverse babel-traverse babel-types magic-string
import {ConfigEnv, Plugin, TransformResult, UserConfig, ViteDevServer,HmrContext,ModuleNode} from 'vite';
import {BooleanLiteral, CallExpression, Identifier, RegExpLiteral, StringLiteral} from "babel-types";
import {NodePath} from "@babel/traverse";
import Utils from "../utils/index";
import {FileListen} from "../utils/FileListen";

export default function vitePluginRequireChange(includes: string[] = [], excludes: string[] = []): Plugin {
  let alias = {}
  const valPre = '__zhixin__transform__require__context__'
  let count = 0
  let server: ViteDevServer
  return {
    name: "vite:vite-plugin-require-context-change",
    config(config: UserConfig, env: ConfigEnv): UserConfig | void | Promise<UserConfig | void | null> | null {
      // 获取别名路径
      alias = Utils.getAliasPath(config)
      return config;
    },
    configureServer(_server) {
      server = _server
    },
    handleHotUpdate(ctx: HmrContext):Array<ModuleNode> | void | Promise<Array<ModuleNode>> {

    },
    transform(code: string, id: string): Promise<TransformResult> | TransformResult {
      let map = null
      if (id.includes('node_modules') && !includes.some(item => id.includes(item)) || excludes.some(item => id.includes(item))) {
        return {code, map}
      }
      if (/.js$|.jsx$|.ts$|.tsx$|.vue$/.test(id)) { // 支持require.context
        const ast = Utils.getJsAst(code)
        const s = Utils.getMagicString(code)
        Utils.jsAstTraverse(ast, {
          CallExpression(ipath: NodePath<CallExpression>) {
            const node = ipath.node;
            const callee = node.callee;
            const arguments2 = node.arguments;
            if (callee.type === 'MemberExpression') {
              const object = callee.object as Identifier;
              const property = callee.property as Identifier;
              if (object?.name === 'require' && property?.name === 'context') { // 找到require.context
                // 获取参数
                const arguments1 = arguments2;
                let importValue: string = (arguments1[0] as StringLiteral).value
                const hasChild: boolean = (arguments1[1] as BooleanLiteral).value
                let pattern: string = (arguments1[2] as RegExpLiteral).pattern
                let sync: string
                if (arguments1.length === 4) {
                  if (arguments1[3].type === 'StringLiteral') {
                    sync = (arguments1[3] as StringLiteral).value
                  } else {
                    console.log('require.context 第4个参数为 sync 或者 lazy')
                  }
                }
                const basePath = Utils.getBasePath(alias, id, importValue);
                FileListen.viteAddDirListen(basePath, id, server)
                const files = Utils.readDirectory(basePath, hasChild, new RegExp(pattern))
                let fenge = ''
                if (Utils.nodeAddFenge(ipath.parent)) {
                  fenge = ';'
                }
                let all = ''
                if (sync === 'lazy') { // 判断是不是异步的
                  Object.keys(files).forEach(key => {
                    all += `'${key}': ()=>import('${files[key]}'),`
                  })
                } else {
                  Object.keys(files).forEach(key => {
                    const valName = (valPre + count++)
                    s.prepend(`import * as ${valName} from '${files[key]}';\n`)
                    all += `'${key}': ${valName},`
                  })
                }
                importValue = `${fenge}(()=>{
  const all = {${all}}
  function Module(file) {
    return ${sync === 'lazy' ? 'all[file]()' : 'all[file]'}
  }
  Module.keys = () => {
    return Object.keys(all)
  }
  Module.id = "${id}"
  return Module
})()`
                s.overwrite(node.start, node.end, importValue)
              }
            }
          },
        })
        map = Utils.getsouceMap(s, code)
        code = s.toString()
      }
      return {
        code,
        map
      };
    },
  }
}
// 支持require.context
// require.context(
//   // 其组件目录的相对路径
//   '@/views/select-object',
//   // 是否查询其子目录
//   false,
//   // 匹配基础组件文件名的正则表达式
//   /\w+\.(vue|js)$/
// ) ---> import.meta.globEager('@/views/select-object/*') 后面的正则额外去匹配


// const coms = [
// require.context('./RenderType', false, /.js$/),
// require.context('./RenderType', false, /.js$/)
// ]
